package com.devunion.bogdan.model.project;

import com.devunion.bogdan.model.event.PageListener;
import com.devunion.bogdan.model.event.PageEvent;

import javax.swing.event.EventListenerList;
import javax.persistence.*;
import java.util.List;
import java.util.ArrayList;
import java.util.Collections;

import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.LazyCollectionOption;
import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.IndexColumn;

/**
 * @author Viktar Liaskovich
 */
@Entity
public class Paper {
    @Id
    @GeneratedValue
    @Column(name = "paperId")
    private long paperId;

//    @ManyToOne
//    @JoinColumn(name = "projectId", updatable = false, insertable = false)
//    private Project project;

    @OneToOne(cascade = CascadeType.ALL)
    private PaperInfo info;

    @OneToMany(cascade=CascadeType.ALL)
    @Cascade({org.hibernate.annotations.CascadeType.ALL})
    @LazyCollection(LazyCollectionOption.FALSE)
    @IndexColumn(name="IND_COL")
    private List<Page> pages = new ArrayList<Page>();

    protected transient EventListenerList listenerList = new EventListenerList();

    public long getPaperId() {
        return paperId;
    }

    public void setPaperId(long paperId) {
        this.paperId = paperId;
    }

//    public Project getProject() {
//        return project;
//    }
//
//    public void setProject(Project project) {
//        this.project = project;
//    }
//
    public PaperInfo getInfo() {
        return info;
    }

    public void setInfo(PaperInfo info) {
        this.info = info;
    }

    public void addPage(Page page) {
        if (page == null) {
            throw new IllegalArgumentException("Page can't be null");
        }

        pages.add(page);

        firePageAddedEvent(new PageEvent(this, page));
    }

    public void removePage(Page page) {
        boolean wasRemoved = pages.remove(page);

        if (wasRemoved) {
            firePageRemovedEvent(new PageEvent(this, page));
        } else {
            throw new IllegalArgumentException("Page " + page + " doesn't exists in the paper " + this);
        }
    }

    public Page getLastPage() {
        if(pages == null || pages.isEmpty()) {
            return null;
        }

        return pages.get(pages.size()-1);
    }

    public List<Page> getPages() {
        return Collections.unmodifiableList(pages);
    }

    public void addPaperListener(PageListener listener) {
        listenerList.add(PageListener.class, listener);
    }

    public void removePaperListener(PageListener listener) {
        listenerList.remove(PageListener.class, listener);
    }

    public PageListener[] getPaperListeners() {
        return listenerList.getListeners(PageListener.class);
    }

    void firePageAddedEvent(PageEvent e) {
        // Guaranteed to return a non-null array
        Object[] listeners = listenerList.getListenerList();

        // Process the listeners last to first, notifying
        // those that are interested in this event
        for (int i = listeners.length - 1; i >= 0; i--) {
            if (listeners[i] == PageListener.class) {
                ((PageListener) listeners[i + 1]).pageAdded(e);
            }
        }
    }

    void firePageRemovedEvent(PageEvent e) {
        // Guaranteed to return a non-null array
        Object[] listeners = listenerList.getListenerList();

        // Process the listeners last to first, notifying
        // those that are interested in this event
        for (int i = listeners.length - 1; i >= 0; i--) {
            if (listeners[i] == PageListener.class) {
                ((PageListener) listeners[i + 1]).pageRemoved(e);
            }
        }
    }

    public void resendEvents() {
        for (Page page : pages) {
            firePageAddedEvent(new PageEvent(this, page));
            page.resendEvents();
        }
    }

    public String toString() {
        return "Title: " + info.getTitle() + ", Author: " + info.getAuthor();
    }
}
